home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
vim
/
src
/
tag.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-09
|
12KB
|
495 lines
/* vi:ts=4:sw=4
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Read the file "credits.txt" for a list of people who contributed.
* Read the file "uganda.txt" for copying and usage conditions.
*/
/*
* Code to handle tags and the tag stack
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
static int findtag __ARGS((char_u *));
static char_u *bottommsg = (char_u *)"at bottom of tag stack";
static char_u *topmsg = (char_u *)"at top of tag stack";
/*
* Jump to tag; handling of tag stack
*
* *tag != NUL (:tag): jump to new tag, add to tag stack
* type == 1 (:pop) || type == 2 (CTRL-T): jump to old position
* type == 0 (:tag): jump to old tag
*/
void
dotag(tag, type, count)
char_u *tag;
int type;
int count;
{
int i;
struct taggy *tagstack = curwin->w_tagstack;
int tagstackidx = curwin->w_tagstackidx;
int tagstacklen = curwin->w_tagstacklen;
if (*tag != NUL) /* new pattern, add to the stack */
{
/*
* if last used entry is not at the top, delete all tag stack entries
* above it.
*/
while (tagstackidx < tagstacklen)
free(tagstack[--tagstacklen].tagname);
/* if tagstack is full: remove oldest entry */
if (++tagstacklen > TAGSTACKSIZE)
{
tagstacklen = TAGSTACKSIZE;
free(tagstack[0].tagname);
for (i = 1; i < tagstacklen; ++i)
tagstack[i - 1] = tagstack[i];
--tagstackidx;
}
/*
* put the tag name in the tag stack
* the position is added below
*/
tagstack[tagstackidx].tagname = strsave(tag);
}
else if (tagstacklen == 0) /* empty stack */
{
EMSG("tag stack empty");
goto end_dotag;
}
else if (type) /* go to older position */
{
if ((tagstackidx -= count) < 0)
{
emsg(bottommsg);
if (tagstackidx + count == 0)
{
/* We did ^T (or <num>^T) from the bottom of the stack */
tagstackidx = 0;
goto end_dotag;
}
/* We weren't at the bottom of the stack, so jump all the way to
* the bottom.
*/
tagstackidx = 0;
}
else if (tagstackidx >= tagstacklen) /* must have been count == 0 */
{
emsg(topmsg);
goto end_dotag;
}
if (tagstack[tagstackidx].fmark.fnum != curbuf->b_fnum) /* jump to other file */
{
if (buflist_getfile(tagstack[tagstackidx].fmark.fnum, tagstack[tagstackidx].fmark.mark.lnum, TRUE) == FAIL)
{
/* emsg(e_notopen); */
goto end_dotag;
}
}
else
curwin->w_cursor.lnum = tagstack[tagstackidx].fmark.mark.lnum;
curwin->w_cursor.col = tagstack[tagstackidx].fmark.mark.col;
curwin->w_set_curswant = TRUE;
goto end_dotag;
}
else /* go to newer pattern */
{
if ((tagstackidx += count - 1) >= tagstacklen)
{
tagstackidx = tagstacklen - 1;
emsg(topmsg);
}
else if (tagstackidx < 0) /* must have been count == 0 */
{
emsg(bottommsg);
tagstackidx = 0;
goto end_dotag;
}
}
/*
* For :tag [arg], remember position before the jump
*/
if (type == 0)
{
tagstack[tagstackidx].fmark.mark = curwin->w_cursor;
tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum;
}
if (findtag(tagstack[tagstackidx].tagname) > 0)
++tagstackidx;
end_dotag:
curwin->w_tagstackidx = tagstackidx;
curwin->w_tagstacklen = tagstacklen;
}
/*
* Print the tag stack
*/
void
dotags()
{
int i;
char_u *name;
struct taggy *tagstack = curwin->w_tagstack;
int tagstackidx = curwin->w_tagstackidx;
int tagstacklen = curwin->w_tagstacklen;
gotocmdline(TRUE, NUL);
msg_outstr((char_u *)"\n # TO tag FROM line in file\n");
for (i = 0; i < tagstacklen; ++i)
{
if (tagstack[i].tagname != NULL)
{
name = fm_getname(&(tagstack[i].fmark));
if (name == NULL) /* file name not available */
continue;
sprintf((char *)IObuff, "%c%2d %-15s %4ld %s\n",
i == tagstackidx ? '>' : ' ',
i + 1,
tagstack[i].tagname,
tagstack[i].fmark.mark.lnum,
name);
msg_outstr(IObuff);
}
flushbuf(); /* show one line at a time */
}
if (tagstackidx == tagstacklen) /* idx at top of stack */
msg_outstr((char_u *)">\n");
wait_return(FALSE);
}
/*
* findtag(tag) - goto tag
* return 0 for failure, 1 for success
*/
static int
findtag(tag)
char_u *tag;
{
FILE *tp;
char_u lbuf[LSIZE];
char_u pbuf[LSIZE]; /* search pattern buffer */
char_u *fname, *str;
int cmplen;
char_u *m = (char_u *)"No tags file";
char_u *marg = NULL;
register char_u *p;
char_u *p2;
char_u *np; /* pointer into file name string */
char_u sbuf[CMDBUFFSIZE + 1]; /* tag file name */
int i;
int save_secure;
int save_p_ws;
if (tag == NULL) /* out of memory condition */
return 0;
if ((cmplen = p_tl) == 0)
cmplen = 999;
/* get stack of tag file names from tags option */
for (np = p_tags; *np; )
{
for (i = 0; i < CMDBUFFSIZE && *np; ++i) /* copy next file name into lbuf */
{
if (*np == ' ')
{
++np;
break;
}
sbuf[i] = *np++;
}
sbuf[i] = 0;
if ((tp = fopen((char *)sbuf, "r")) == NULL)
continue;
reg_ic = p_ic; /* for cstrncmp() */
while (fgets((char *)lbuf, LSIZE, tp) != NULL)
{
m = (char_u *)"Format error in tags file %s"; /* default error message */
marg = sbuf;
/* find start of file name, after first white space */
fname = lbuf;
skiptospace(&fname); /* skip tag */
if (*fname == NUL)
goto erret;
*fname++ = '\0';
if (cstrncmp(lbuf, tag, cmplen) == 0) /* Tag found */
{
fclose(tp);
skipspace(&fname);
/* find start of search command, after second white space */
str = fname;
skiptospace(&str);
if (*str == NUL)
goto erret;
*str++ = '\0';
skipspace(&str);
/*
* If the command is a string like "/^function fname"
* scan through the search string. If we see a magic
* char, we have to quote it. This lets us use "real"
* implementations of ctags.
*/
if (*str == '/' || *str == '?')
{
p = pbuf;
*p++ = *str++; /* copy the '/' or '?' */
if (*str == '^')
*p++ = *str++; /* copy the '^' */
while (*str)
{
switch (*str)
{
case '\\': if (str[1] == '(') /* remove '\' before '(' */
++str;
else
*p++ = *str++;
break;
case '\r':
case '\n': *str = pbuf[0]; /* copy '/' or '?' */
str[1] = NUL; /* delete NL after CR */
break;
/*
* if string ends in search character: skip it
* else escape it with '\'
*/
case '/':
case '?': if (*str != pbuf[0]) /* not the search char */
break;
/* last char */
if (str[1] == '\n' || str[1] == '\r')
{
++str;
continue;
}
case '[':
if (!p_magic)
break;
case '^':
case '*':
case '.': *p++ = '\\';
break;
}
*p++ = *str++;
}
}
else /* not a search command, just copy it */
for (p = pbuf; *str && *str != '\n'; )
*p++ = *str++;
*p = NUL;
/*
* expand filename (for environment variables)
*/
if ((p = ExpandOne((char_u *)fname, 1, -1)) != NULL)
fname = p;
/*
* if 'tagrelative' option set, may change file name
*/
if (p_tr && !isFullName(fname) && (p2 = gettail(sbuf)) != sbuf)
{
STRNCPY(p2, fname, CMDBUFFSIZE - (p2 - sbuf));
fname = sbuf;
}
/*
* check if file for tag exists before abandoning current file
*/
if (getperm(fname) < 0)
{
m = (char_u *)"File \"%s\" does not exist";
marg = fname;
goto erret;
}
RedrawingDisabled = TRUE;
/*
* if it was a CTRL-W CTRL-] command split window now
*/
if (postponed_split)
win_split(0L, FALSE);
i = getfile(fname, NULL, TRUE, (linenr_t)0);
if (p)
free(p);
if (i <= 0)
{
curwin->w_set_curswant = TRUE;
postponed_split = FALSE;
RedrawingDisabled = FALSE;
save_secure = secure;
secure = 1;
tag_busy = TRUE; /* don't set marks for this search */
keep_old_search_pattern = TRUE;
/*
* if the command is a search, try here
*
* Rather than starting at line one, just turn wrap-scan
* on temporarily, this ensures that tags on line 1 will
* be found, and makes sure our guess searches search the
* whole file when repeated -- webb.
*/
if (pbuf[0] == '/' || pbuf[0] == '?')
{
save_p_ws = p_ws;
p_ws = TRUE; /* Switch wrap-scan on temporarily */
if (!dosearch(pbuf[0], pbuf + 1, FALSE, (long)1, FALSE, FALSE))
{
register int notfound = FALSE;
/*
* Failed to find pattern, take a guess:
*/
sprintf((char *)pbuf, "^%s(", lbuf);
if (!dosearch('/', pbuf, FALSE, (long)1, FALSE, FALSE))
{
/* Guess again: */
sprintf((char *)pbuf, "^[#a-zA-Z_].*%s(", lbuf);
if (!dosearch('/', pbuf, FALSE, (long)1, FALSE, FALSE))
notfound = TRUE;
}
if (notfound)
EMSG("Can't find tag pattern");
else
{
MSG("Couldn't find tag, just guessing!");
sleep(1);
}
}
p_ws = save_p_ws;
}
else
{
curwin->w_cursor.lnum = 1; /* start command in line 1 */
docmdline(pbuf);
}
tag_busy = FALSE;
keep_old_search_pattern = FALSE;
if (secure == 2) /* done something that is not allowed */
wait_return(TRUE);
secure = save_secure;
/* print the file message after redraw */
if (p_im && i == -1)
stuffReadbuff((char_u *)"\033\007i"); /* ESC CTRL-G i */
else
stuffcharReadbuff('\007'); /* CTRL-G */
return 1;
}
RedrawingDisabled = FALSE;
if (postponed_split) /* close the window */
{
close_window(FALSE);
postponed_split = FALSE;
}
return 0;
}
}
m = NULL;
erret:
fclose(tp);
if (m)
emsg2(m, marg);
}
if (m == NULL)
EMSG("tag not found");
else if (marg == NULL)
emsg(m);
return 0;
}
#ifdef WEBB_COMPLETE
int
ExpandTags(prog, num_file, file)
regexp *prog;
int *num_file;
char_u ***file;
{
char_u **matches, **new_matches;
char_u tag_file[CMDBUFFSIZE + 1];
char_u line[LSIZE];
char_u *np;
char_u *p;
int limit = 100;
int index;
int i;
int lnum;
FILE *fp;
matches = (char_u **) alloc((unsigned)(limit * sizeof(char_u *)));
if (matches == NULL)
return FAIL;
index = 0;
for (np = p_tags; *np; )
{
for (i = 0; i < CMDBUFFSIZE && *np && *np != ' '; i++)
tag_file[i] = *np++;
tag_file[i] = NUL;
skipspace(&np);
if ((fp = fopen((char *)tag_file, "r")) == NULL)
continue;
lnum = 0;
while (!vim_fgets(line, LSIZE, fp, &lnum))
{
if (regexec(prog, line, TRUE))
{
p = line;
skiptospace(&p);
*p = NUL;
if (index == limit)
{
limit *= 2;
new_matches = (char_u **) alloc((unsigned)(limit * sizeof(char_u *)));
if (new_matches == NULL)
{
/* We'll miss some matches, oh well */
*file = matches;
*num_file = index;
return OK;
}
for (i = 0; i < index; i++)
new_matches[i] = matches[i];
free(matches);
matches = new_matches;
}
matches[index++] = strsave(line);
}
}
}
if (index > 0)
{
new_matches = *file = (char_u **) alloc((unsigned)(index * sizeof(char_u *)));
if (new_matches == NULL)
{
*file = matches;
*num_file = index;
return OK;
}
for (i = 0; i < index; i++)
new_matches[i] = matches[i];
}
free(matches);
*num_file = index;
return OK;
}
#endif /* WEBB_COMPLETE */